<template>
	<div class="chat-input-area">
		<div :class="['edit-chat-container',isEmpty?'':'not-empty']" contenteditable="true" @paste.prevent="onPaste"
			@keydown="onKeydown" @compositionstart="compositionFlag=true" @compositionend="onCompositionEnd"
			@input="onEditorInput" @mousedown="onMousedown" ref="content" @blur="onBlur">
		</div>
		<chat-at-box @select="onAtSelect" :search-text="atSearchText" ref="atBox" :ownerId="ownerId"
			:members="groupMembers"></chat-at-box>
	</div>
</template>

<script>
	import ChatAtBox from "./ChatAtBox";

	export default {
		name: "ChatInput",
		components: { ChatAtBox },
		props: {
			ownerId: {
				type: Number,
			},
			groupMembers: {
				type: Array,
			},
		},
		data() {
			return {
				imageList: [],
				fileList: [],
				currentId: 0,
				atSearchText: null,
				compositionFlag: false,
				atIng: false,
				isEmpty: true,
				changeStored: true,
				blurRange: null
			}
		},
		methods: {
			onPaste(e) {
				this.isEmpty = false;
				let txt = e.clipboardData.getData('Text')
				let range = window.getSelection().getRangeAt(0)
				if (range.startContainer !== range.endContainer || range.startOffset !== range.endOffset) {
					range.deleteContents();
				}
				// 粘贴图片和文件时，这里没有数据
				if (txt && typeof(txt) == 'string') {
					let textNode = document.createTextNode(txt);
					range.insertNode(textNode)
					range.collapse();
					return;
				}
				let items = (e.clipboardData || window.clipboardData).items
				if (items.length) {
					for (let i = 0; i < items.length; i++) {
						if (items[i].type.indexOf('image') !== -1) {
							let file = items[i].getAsFile();
							let imagePush = {
								fileId: this.generateId(),
								file: file,
								url: URL.createObjectURL(file)
							};
							this.imageList[imagePush.fileId] = (imagePush);
							let line = this.newLine();
							let imageElement = document.createElement('img');
							imageElement.className = 'chat-image no-text';
							imageElement.src = imagePush.url;
							imageElement.dataset.imgId = imagePush.fileId;
							line.appendChild(imageElement);
							let after = document.createTextNode('\u00A0');
							line.appendChild(after);
							this.selectElement(after, 1);		
						} else {
							let asFile = items[i].getAsFile();
							if (!asFile) {
								continue;
							}
							let filePush = { fileId: this.generateId(), file: asFile };
							this.fileList[filePush.fileId] = (filePush)
							let line = this.newLine();
							let fileElement = this.createFile(filePush);
							line.appendChild(fileElement);
							let after = document.createTextNode('\u00A0');
							line.appendChild(after);
							this.selectElement(after, 1);
						}
					}
				}
				range.collapse();
			},
			selectElement(element, endOffset) {
				let selection = window.getSelection();
				// 插入元素可能不是立即执行的，vue可能会在插入元素后再更新dom
				this.$nextTick(() => {
					let t1 = document.createRange();
					t1.setStart(element, 0);
					t1.setEnd(element, endOffset || 0);
					if (element.firstChild) {
						t1.selectNodeContents(element.firstChild);
					}
					t1.collapse();
					selection.removeAllRanges();
					selection.addRange(t1);
					// 需要时自动聚焦
					if (element.focus) {
						element.focus();
					}
				})
			},
			onCompositionEnd(e) {
				this.compositionFlag = false;
				this.onEditorInput(e);
			},
			onKeydown(e) {
				if (e.keyCode === 13) {
					e.preventDefault();
					e.stopPropagation();
					if (this.atIng) {
						console.log('选中at的人')
						this.$refs.atBox.select();
						return;
					}
					if (e.ctrlKey) {
						let line = this.newLine();
						let after = document.createTextNode('\u00A0');
						line.appendChild(after);
						this.selectElement(line.childNodes[0], 0);
					} else {
						// 中文输入标记
						if (this.compositionFlag) {
							return;
						}
						this.submit();
					}
					return;
				}
				// 删除键
				if (e.keyCode === 8) {
					console.log("delete")
					// 等待dom更新
					setTimeout(() => {
						let s = this.$refs.content.innerHTML.trim();
						// 空dom时，需要刷新dom
						console.log(s);
						if (s === '' || s === '<br>' || s === '<div>&nbsp;</div>' ) {
							// 拼接随机长度的空格，以刷新dom
							this.empty();
							this.isEmpty = true;
							this.selectElement(this.$refs.content);
						} else {
							this.isEmpty = false;
						}
					})
				}
				// at框打开时，上下键移动特殊处理
				if (this.atIng) {
					if (e.keyCode === 38) {
						e.preventDefault();
						e.stopPropagation();
						this.$refs.atBox.moveUp();
					}
					if (e.keyCode === 40) {
						e.preventDefault();
						e.stopPropagation();
						this.$refs.atBox.moveDown();
					}
				}

			},
			onAtSelect(member) {
				this.atIng = false;
				// 选中输入的 @xx 符
				let blurRange = this.blurRange;
				let endContainer = blurRange.endContainer
				let startOffset = endContainer.data.indexOf("@"+this.atSearchText);
				let endOffset = startOffset + this.atSearchText.length + 1;
				blurRange.setStart(blurRange.endContainer, startOffset);
				blurRange.setEnd(blurRange.endContainer,  endOffset);
				blurRange.deleteContents()
				blurRange.collapse();
				console.log("onAtSelect")
				this.focus();
				// 创建元素节点
				let element = document.createElement('SPAN')
				element.className = "chat-at-user";
				element.dataset.id = member.userId;
				element.contentEditable = 'false'
				element.innerText = `@${member.showNickName}`
				blurRange.insertNode(element)
				// 光标移动到末尾
				blurRange.collapse()

				// 插入空格
				let textNode = document.createTextNode('\u00A0');
				blurRange.insertNode(textNode);

				blurRange.collapse()
				this.atSearchText = "";
				this.selectElement(textNode, 1);
			},
			onEditorInput(e) {
				this.isEmpty = false;
				this.changeStored = false;
				if (this.$props.groupMembers && !this.compositionFlag) {
					let selection = window.getSelection()
					let range = selection.getRangeAt(0);
					// 截取@后面的名称作为过滤条件，并以空格结束
					let endContainer = range.endContainer;
					let endOffset = range.endOffset;
					let textContent = endContainer.textContent;
					let startIndex = -1;
					for (let i = endOffset; i >= 0; i--) {
						if (textContent[i] === '@') {
							startIndex = i;
							break;
						}
					}
					// 没有at符号，则关闭弹窗
					if (startIndex === -1) {
						this.$refs.atBox.close();
						return;
					}

					let endIndex = endOffset;
					for (let i = endOffset; i < textContent.length; i++) {
						if (textContent[i] === ' ') {
							endIndex = i;
							break;
						}
					}
					this.atSearchText = textContent.substring(startIndex + 1, endIndex).trim();
					// 打开选择弹窗
					if (this.atSearchText == '') {
						this.showAtBox(e)
					}
				}

			},
			onBlur(e) {
				this.updateRange();
				
			},
			onMousedown() {
				if (this.atIng) {
					this.$refs.atBox.close();
					this.atIng = false;
				}
			},
			insertEmoji(emojiText) {
				let emojiElement = document.createElement('img');
				emojiElement.className = 'chat-emoji no-text';
				emojiElement.dataset.emojiCode = emojiText;
				emojiElement.src = this.$emo.textToUrl(emojiText);

				let blurRange = this.blurRange;
				if (!blurRange) {
					this.focus();
					this.updateRange();
					blurRange = this.blurRange;
				}
				if (blurRange.startContainer !== blurRange.endContainer || blurRange.startOffset !== blurRange.endOffset) {
					blurRange.deleteContents();
				}
				blurRange.insertNode(emojiElement);
				blurRange.collapse()

				let textNode = document.createTextNode('\u00A0');
				blurRange.insertNode(textNode)
				blurRange.collapse()

				this.selectElement(textNode);
				this.updateRange();
				this.isEmpty = false;
			},
			generateId() {
				return this.currentId++;
			},
			createFile(filePush) {
				let file = filePush.file;
				let fileId = filePush.fileId;
				let container = document.createElement('div');
				container.className = 'chat-file-container no-text';
				container.contentEditable = 'false';
				container.dataset.fileId = fileId;

				let left = document.createElement('div');
				left.className = 'file-position-left';
				container.appendChild(left);

				let icon = document.createElement('div');
				icon.className = 'el-icon-document';
				left.appendChild(icon);

				let right = document.createElement('div');
				right.className = 'file-position-right';
				container.appendChild(right);

				let fileName = document.createElement('div');
				fileName.className = 'file-name';
				fileName.innerText = file.name;

				let fileSize = document.createElement('div');
				fileSize.className = 'file-size';
				fileSize.innerText = this.sizeConvert(file.size);

				right.appendChild(fileName);
				right.appendChild(fileSize);

				return container;
			},
			sizeConvert(len) {
				if (len < 1024) {
					return len + 'B';
				} else if (len < 1024 * 1024) {
					return (len / 1024).toFixed(2) + 'KB';
				} else if (len < 1024 * 1024 * 1024) {
					return (len / 1024 / 1024).toFixed(2) + 'MB';
				} else {
					return (len / 1024 / 1024 / 1024).toFixed(2) + 'GB';
				}
			},
			updateRange() {
				let selection = window.getSelection();
				this.blurRange = selection.getRangeAt(0);
			},
			newLine() {
				let selection = window.getSelection();
				let range = selection.getRangeAt(0);
				let divElement = document.createElement('div');
				let endContainer = range.endContainer;
				let parentElement = endContainer.parentElement;
				if (parentElement.parentElement === this.$refs.content) {
					divElement.innerHTML  = endContainer.textContent.substring(range.endOffset).trim(); 
					endContainer.textContent = endContainer.textContent.substring(0, range.endOffset);
					// 插入到当前div（当前行）后面
					parentElement.insertAdjacentElement('afterend', divElement);
				} else {
					divElement.innerHTML = '';
					this.$refs.content.append(divElement);
				}
				return divElement;
			},
			clear() {
				this.empty();
				this.imageList = [];
				this.fileList = [];
			},
			empty() {
				this.$refs.content.innerHTML = "";
				let line = this.newLine();
				let after = document.createTextNode('\u00A0');
				line.appendChild(after);
				this.$nextTick(()=>this.selectElement(after));
			},
			showAtBox(e) {
				this.atIng = true;
				// show之后会自动更新当前搜索的text
				// this.atSearchText = "";
				let selection = window.getSelection()
				let range = selection.getRangeAt(0)
				// 光标所在坐标
				let pos = range.getBoundingClientRect();
				this.$refs.atBox.open({
					x: pos.x,
					y: pos.y
				})
				// 记录光标所在位置
				this.updateRange();
			},
			html2Escape(strHtml) {
				return strHtml.replace(/[<>&"]/g, function(c) {
					return {
						'<': '&lt;',
						'>': '&gt;',
						'&': '&amp;',
						'"': '&quot;'
					} [c];
				});
			},
			submit() {
				let nodes = this.$refs.content.childNodes;
				let fullList = [];
				let tempText = '';
				let atUserIds = [];
				let each = (nodes) => {
					for (let i = 0; i < nodes.length; i++) {
						let node = nodes[i];
						if (!node) {
							continue;
						}
						if (node.nodeType === 3) {
							tempText += this.html2Escape(node.textContent);
							continue;
						}
						let nodeName = node.nodeName.toLowerCase();
						if (nodeName === 'script') {
							continue;
						}
						let text = tempText.trim();
						if (nodeName === 'img') {
							let imgId = node.dataset.imgId;
							if (imgId) {
								if (text) {
									fullList.push({
										type: 'text',
										content: text,
										atUserIds: atUserIds
									})
									tempText = '';
									atUserIds = []
								}
								fullList.push({
									type: 'image',
									content: this.imageList[imgId]
								})
							} else {
								let emojiCode = node.dataset.emojiCode;
								tempText += emojiCode;
							}
						} else if (nodeName === 'div') {
							let fileId = node.dataset.fileId
							// 文件
							if (fileId) {
								if (text) {
									fullList.push({
										type: 'text',
										content: text,
										atUserIds: atUserIds
									})
									tempText = '';
									atUserIds = []
								}
								fullList.push({
									type: 'file',
									content: this.fileList[fileId]
								})
							} else {
								tempText += '\n';
								each(node.childNodes);
							}
						} else if (nodeName === 'span') {
							if(node.dataset.id){
								tempText += node.innerHTML;
								atUserIds.push(node.dataset.id)
							}else {
								tempText += node.outerHtml;
							}
						}
					}
				}
				each(nodes)
				let text = tempText.trim();
				if (text !== '') {
					fullList.push({
						type: 'text',
						content: text,
						atUserIds: atUserIds
					})
				}
				this.$emit('submit', fullList);
			},
			focus() {
				this.$refs.content.focus();
			}

		}
	}
</script>

<style lang="scss">
	.chat-input-area {
		width: 100%;
		height: 100%;
		position: relative;

		.edit-chat-container {
			position: absolute;
			top: 0;
			left: 0;
			right: 0;
			bottom: 0;
			border: 1px solid #c3c3c3;
			outline: none;
			padding: 5px;
			line-height: 30px;
			font-size: 16px;
			text-align: left;
			overflow-y: scroll;

			// 单独一行时，无法在前面输入的bug
			>div:before {
				content: "\00a0";
				font-size: 14px;
				position: absolute;
				top: 0;
				left: 0;
			}

			.chat-image {
				display: block;
				max-width: 200px;
				max-height: 100px;
				border: 1px solid #e6e6e6;
				cursor: pointer;
			}

			.chat-emoji {
				width: 30px;
				height: 30px;
				vertical-align: top;
				cursor: pointer;
			}

			.chat-file-container {
				max-width: 65%;
				padding: 10px;
				border: 2px solid #587ff0;
				display: flex;
				background: #eeeC;
				border-radius: 10px;

				.file-position-left {
					display: flex;
					width: 80px;
					justify-content: center;
					align-items: center;

					.el-icon-document {
						font-size: 40px;
						text-align: center;
						color: #d42e07;
					}
				}

				.file-position-right {
					flex: 1;

					.file-name {
						font-size: 16px;
						font-weight: 600;
						color: #66b1ff;
					}

					.file-size {
						font-size: 14px;
						font-weight: 600;
						color: black;
					}
				}
			}

			.chat-at-user {
				color: #00f;
				font-weight: 600;

				border-radius: 3px;
			}
		}

		.edit-chat-container>div:nth-of-type(1):after {
			content: '请输入消息（按Ctrl+Enter键换行）';
			color: gray;
		}

		.edit-chat-container.not-empty>div:nth-of-type(1):after {
			content: none;
		}

	}
</style>